1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.collect.CollectPreconditions.checkNonnegative;
20 import static com.google.common.collect.CollectPreconditions.checkRemove;
21
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.annotations.VisibleForTesting;
24 import com.google.common.base.Objects;
25
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.ConcurrentModificationException;
29 import java.util.Iterator;
30 import java.util.LinkedHashMap;
31 import java.util.LinkedHashSet;
32 import java.util.Map;
33 import java.util.NoSuchElementException;
34 import java.util.Set;
35
36 import javax.annotation.Nullable;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 @GwtCompatible(serializable = true, emulated = true)
78 public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
79
80
81
82
83
84 public static <K, V> LinkedHashMultimap<K, V> create() {
85 return new LinkedHashMultimap<K, V>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY);
86 }
87
88
89
90
91
92
93
94
95
96
97 public static <K, V> LinkedHashMultimap<K, V> create(
98 int expectedKeys, int expectedValuesPerKey) {
99 return new LinkedHashMultimap<K, V>(
100 Maps.capacity(expectedKeys),
101 Maps.capacity(expectedValuesPerKey));
102 }
103
104
105
106
107
108
109
110
111
112
113 public static <K, V> LinkedHashMultimap<K, V> create(
114 Multimap<? extends K, ? extends V> multimap) {
115 LinkedHashMultimap<K, V> result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY);
116 result.putAll(multimap);
117 return result;
118 }
119
120 private interface ValueSetLink<K, V> {
121 ValueSetLink<K, V> getPredecessorInValueSet();
122 ValueSetLink<K, V> getSuccessorInValueSet();
123
124 void setPredecessorInValueSet(ValueSetLink<K, V> entry);
125 void setSuccessorInValueSet(ValueSetLink<K, V> entry);
126 }
127
128 private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
129 pred.setSuccessorInValueSet(succ);
130 succ.setPredecessorInValueSet(pred);
131 }
132
133 private static <K, V> void succeedsInMultimap(
134 ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
135 pred.setSuccessorInMultimap(succ);
136 succ.setPredecessorInMultimap(pred);
137 }
138
139 private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
140 succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
141 }
142
143 private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
144 succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
145 }
146
147
148
149
150
151
152
153 @VisibleForTesting
154 static final class ValueEntry<K, V> extends ImmutableEntry<K, V>
155 implements ValueSetLink<K, V> {
156 final int smearedValueHash;
157
158 @Nullable ValueEntry<K, V> nextInValueBucket;
159
160 ValueSetLink<K, V> predecessorInValueSet;
161 ValueSetLink<K, V> successorInValueSet;
162
163 ValueEntry<K, V> predecessorInMultimap;
164 ValueEntry<K, V> successorInMultimap;
165
166 ValueEntry(@Nullable K key, @Nullable V value, int smearedValueHash,
167 @Nullable ValueEntry<K, V> nextInValueBucket) {
168 super(key, value);
169 this.smearedValueHash = smearedValueHash;
170 this.nextInValueBucket = nextInValueBucket;
171 }
172
173 boolean matchesValue(@Nullable Object v, int smearedVHash) {
174 return smearedValueHash == smearedVHash && Objects.equal(getValue(), v);
175 }
176
177 @Override
178 public ValueSetLink<K, V> getPredecessorInValueSet() {
179 return predecessorInValueSet;
180 }
181
182 @Override
183 public ValueSetLink<K, V> getSuccessorInValueSet() {
184 return successorInValueSet;
185 }
186
187 @Override
188 public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
189 predecessorInValueSet = entry;
190 }
191
192 @Override
193 public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
194 successorInValueSet = entry;
195 }
196
197 public ValueEntry<K, V> getPredecessorInMultimap() {
198 return predecessorInMultimap;
199 }
200
201 public ValueEntry<K, V> getSuccessorInMultimap() {
202 return successorInMultimap;
203 }
204
205 public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
206 this.successorInMultimap = multimapSuccessor;
207 }
208
209 public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
210 this.predecessorInMultimap = multimapPredecessor;
211 }
212 }
213
214 private static final int DEFAULT_KEY_CAPACITY = 16;
215 private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
216 @VisibleForTesting static final double VALUE_SET_LOAD_FACTOR = 1.0;
217
218 @VisibleForTesting transient int valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
219 private transient ValueEntry<K, V> multimapHeaderEntry;
220
221 private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) {
222 super(new LinkedHashMap<K, Collection<V>>(keyCapacity));
223 checkNonnegative(valueSetCapacity, "expectedValuesPerKey");
224
225 this.valueSetCapacity = valueSetCapacity;
226 this.multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
227 succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
228 }
229
230
231
232
233
234
235
236
237
238
239 @Override
240 Set<V> createCollection() {
241 return new LinkedHashSet<V>(valueSetCapacity);
242 }
243
244
245
246
247
248
249
250
251
252
253 @Override
254 Collection<V> createCollection(K key) {
255 return new ValueSet(key, valueSetCapacity);
256 }
257
258
259
260
261
262
263
264
265
266 @Override
267 public Set<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
268 return super.replaceValues(key, values);
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283 @Override public Set<Map.Entry<K, V>> entries() {
284 return super.entries();
285 }
286
287
288
289
290
291
292
293
294 @Override public Collection<V> values() {
295 return super.values();
296 }
297
298 @VisibleForTesting
299 final class ValueSet extends Sets.ImprovedAbstractSet<V> implements ValueSetLink<K, V> {
300
301
302
303
304
305 private final K key;
306 @VisibleForTesting ValueEntry<K, V>[] hashTable;
307 private int size = 0;
308 private int modCount = 0;
309
310
311
312 private ValueSetLink<K, V> firstEntry;
313 private ValueSetLink<K, V> lastEntry;
314
315 ValueSet(K key, int expectedValues) {
316 this.key = key;
317 this.firstEntry = this;
318 this.lastEntry = this;
319
320 int tableSize = Hashing.closedTableSize(expectedValues, VALUE_SET_LOAD_FACTOR);
321
322 @SuppressWarnings("unchecked")
323 ValueEntry<K, V>[] hashTable = new ValueEntry[tableSize];
324 this.hashTable = hashTable;
325 }
326
327 private int mask() {
328 return hashTable.length - 1;
329 }
330
331 @Override
332 public ValueSetLink<K, V> getPredecessorInValueSet() {
333 return lastEntry;
334 }
335
336 @Override
337 public ValueSetLink<K, V> getSuccessorInValueSet() {
338 return firstEntry;
339 }
340
341 @Override
342 public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
343 lastEntry = entry;
344 }
345
346 @Override
347 public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
348 firstEntry = entry;
349 }
350
351 @Override
352 public Iterator<V> iterator() {
353 return new Iterator<V>() {
354 ValueSetLink<K, V> nextEntry = firstEntry;
355 ValueEntry<K, V> toRemove;
356 int expectedModCount = modCount;
357
358 private void checkForComodification() {
359 if (modCount != expectedModCount) {
360 throw new ConcurrentModificationException();
361 }
362 }
363
364 @Override
365 public boolean hasNext() {
366 checkForComodification();
367 return nextEntry != ValueSet.this;
368 }
369
370 @Override
371 public V next() {
372 if (!hasNext()) {
373 throw new NoSuchElementException();
374 }
375 ValueEntry<K, V> entry = (ValueEntry<K, V>) nextEntry;
376 V result = entry.getValue();
377 toRemove = entry;
378 nextEntry = entry.getSuccessorInValueSet();
379 return result;
380 }
381
382 @Override
383 public void remove() {
384 checkForComodification();
385 checkRemove(toRemove != null);
386 ValueSet.this.remove(toRemove.getValue());
387 expectedModCount = modCount;
388 toRemove = null;
389 }
390 };
391 }
392
393 @Override
394 public int size() {
395 return size;
396 }
397
398 @Override
399 public boolean contains(@Nullable Object o) {
400 int smearedHash = Hashing.smearedHash(o);
401 for (ValueEntry<K, V> entry = hashTable[smearedHash & mask()]; entry != null;
402 entry = entry.nextInValueBucket) {
403 if (entry.matchesValue(o, smearedHash)) {
404 return true;
405 }
406 }
407 return false;
408 }
409
410 @Override
411 public boolean add(@Nullable V value) {
412 int smearedHash = Hashing.smearedHash(value);
413 int bucket = smearedHash & mask();
414 ValueEntry<K, V> rowHead = hashTable[bucket];
415 for (ValueEntry<K, V> entry = rowHead; entry != null;
416 entry = entry.nextInValueBucket) {
417 if (entry.matchesValue(value, smearedHash)) {
418 return false;
419 }
420 }
421
422 ValueEntry<K, V> newEntry = new ValueEntry<K, V>(key, value, smearedHash, rowHead);
423 succeedsInValueSet(lastEntry, newEntry);
424 succeedsInValueSet(newEntry, this);
425 succeedsInMultimap(multimapHeaderEntry.getPredecessorInMultimap(), newEntry);
426 succeedsInMultimap(newEntry, multimapHeaderEntry);
427 hashTable[bucket] = newEntry;
428 size++;
429 modCount++;
430 rehashIfNecessary();
431 return true;
432 }
433
434 private void rehashIfNecessary() {
435 if (Hashing.needsResizing(size, hashTable.length, VALUE_SET_LOAD_FACTOR)) {
436 @SuppressWarnings("unchecked")
437 ValueEntry<K, V>[] hashTable = new ValueEntry[this.hashTable.length * 2];
438 this.hashTable = hashTable;
439 int mask = hashTable.length - 1;
440 for (ValueSetLink<K, V> entry = firstEntry;
441 entry != this; entry = entry.getSuccessorInValueSet()) {
442 ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
443 int bucket = valueEntry.smearedValueHash & mask;
444 valueEntry.nextInValueBucket = hashTable[bucket];
445 hashTable[bucket] = valueEntry;
446 }
447 }
448 }
449
450 @Override
451 public boolean remove(@Nullable Object o) {
452 int smearedHash = Hashing.smearedHash(o);
453 int bucket = smearedHash & mask();
454 ValueEntry<K, V> prev = null;
455 for (ValueEntry<K, V> entry = hashTable[bucket]; entry != null;
456 prev = entry, entry = entry.nextInValueBucket) {
457 if (entry.matchesValue(o, smearedHash)) {
458 if (prev == null) {
459
460 hashTable[bucket] = entry.nextInValueBucket;
461 } else {
462 prev.nextInValueBucket = entry.nextInValueBucket;
463 }
464 deleteFromValueSet(entry);
465 deleteFromMultimap(entry);
466 size--;
467 modCount++;
468 return true;
469 }
470 }
471 return false;
472 }
473
474 @Override
475 public void clear() {
476 Arrays.fill(hashTable, null);
477 size = 0;
478 for (ValueSetLink<K, V> entry = firstEntry;
479 entry != this; entry = entry.getSuccessorInValueSet()) {
480 ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
481 deleteFromMultimap(valueEntry);
482 }
483 succeedsInValueSet(this, this);
484 modCount++;
485 }
486 }
487
488 @Override
489 Iterator<Map.Entry<K, V>> entryIterator() {
490 return new Iterator<Map.Entry<K, V>>() {
491 ValueEntry<K, V> nextEntry = multimapHeaderEntry.successorInMultimap;
492 ValueEntry<K, V> toRemove;
493
494 @Override
495 public boolean hasNext() {
496 return nextEntry != multimapHeaderEntry;
497 }
498
499 @Override
500 public Map.Entry<K, V> next() {
501 if (!hasNext()) {
502 throw new NoSuchElementException();
503 }
504 ValueEntry<K, V> result = nextEntry;
505 toRemove = result;
506 nextEntry = nextEntry.successorInMultimap;
507 return result;
508 }
509
510 @Override
511 public void remove() {
512 checkRemove(toRemove != null);
513 LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue());
514 toRemove = null;
515 }
516 };
517 }
518
519 @Override
520 Iterator<V> valueIterator() {
521 return Maps.valueIterator(entryIterator());
522 }
523
524 @Override
525 public void clear() {
526 super.clear();
527 succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
528 }
529 }
530